// ============================================================================
// 微博工作流服务 - 整合定时任务、爬取和消息队列的完整工作流
// ============================================================================

import { logger } from '@roasmax/logger'
import { TaskScheduler } from '../core/scheduler'
import { TaskManager } from '../tasks/task-manager'
import { RabbitMQManager } from '../core/rabbitmq-manager'
import { ScheduledTaskParams, ScrapeTask } from '../../shared/types'
import { BrowserPoolManager } from '@roasmax/browser'
import { useEntityManager } from '../storage/data-source'
import { Account, Task } from '../storage/entities'
import { creawlLatestWeiboByKeyword } from '../utils/searchTaskExecutor'

/**
 * 工作流配置
 */
export interface WorkflowConfig {
  maxConcurrentKeywords: number
  maxPagesPerKeyword: number
  requestDelay: number
  retryAttempts: number
  batchSize: number
  enableMQ: boolean
}

/**
 * 工作流统计
 */
export interface WorkflowStats {
  totalKeywords: number
  processedKeywords: number
  totalWeibos: number
  successfulWeibos: number
  failedWeibos: number
  startTime: Date
  endTime?: Date
  duration?: number
}

/**
 * 微博工作流服务类
 */
export class WeiboWorkflowService {
  private static instance: WeiboWorkflowService
  private config: WorkflowConfig
  private isRunning = false
  private currentStats: WorkflowStats | null = null

  constructor(
    private scheduler: TaskScheduler,
    config?: Partial<WorkflowConfig>
  ) {
    this.config = {
      maxConcurrentKeywords: 3,
      maxPagesPerKeyword: 5,
      requestDelay: 2000,
      retryAttempts: 3,
      batchSize: 10,
      enableMQ: true,
      ...config
    }
  }

  /**
   * 获取单例实例
   */
  static getInstance(
    scheduler?: TaskScheduler,
    config?: Partial<WorkflowConfig>
  ): WeiboWorkflowService {
    if (!WeiboWorkflowService.instance && scheduler) {
      WeiboWorkflowService.instance = new WeiboWorkflowService(
        scheduler, config
      )
    }
    return WeiboWorkflowService.instance
  }

  /**
   * 创建定时微博爬取任务
   */
  async createScheduledWeiboTask(
    keywords: string[],
    accountId: string,
    options: {
      interval?: number // 执行间隔（毫秒）
      maxPages?: number
      enabled?: boolean
      cronExpression?: string
      count?: number
      dateRange?: [Date, Date]
      includeComments?: boolean
      includeReposts?: boolean
    } = {}
  ): Promise<string> {
    try {
      // 参数验证
      if (!keywords || keywords.length === 0) {
        throw new Error('关键字列表不能为空')
      }

      if (!accountId || accountId.trim() === '') {
        throw new Error('账号ID不能为空')
      }

      // 验证关键字
      const validKeywords = keywords.filter(keyword =>
        keyword && typeof keyword === 'string' && keyword.trim().length > 0
      )

      if (validKeywords.length === 0) {
        throw new Error('没有有效的关键字')
      }

      // 验证账号是否存在
      const account = await useEntityManager(async m => {
        const accountRepo = m.getRepository(Account)
        return await accountRepo.findOne({ where: { id: parseInt(accountId) } })
      })
      if (!account) {
        throw new Error(`账号不存在: ${accountId}`)
      }

      // 验证账号是否有效
      if (!account.isValid) {
        throw new Error(`账号已失效: ${accountId}`)
      }

      // 验证时间间隔
      const interval = options.interval || 30 * 60 * 1000 // 默认30分钟
      if (interval < 60 * 1000) { // 最小1分钟
        throw new Error('执行间隔不能少于1分钟')
      }

      // 验证最大页数
      const maxPages = options.maxPages || this.config.maxPagesPerKeyword
      if (maxPages < 1 || maxPages > 20) {
        throw new Error('最大页数必须在1-20之间')
      }

      // 构建任务参数
      const params: ScheduledTaskParams = {
        keywords: validKeywords,
        interval,
        maxPages,
        enabled: options.enabled !== false,
        cronExpression: options.cronExpression,
        count: options.count,
        dateRange: options.dateRange,
        includeComments: options.includeComments || false,
        includeReposts: options.includeReposts || false
      }

      // 添加定时任务
      const taskId = await this.scheduler.addScheduledTask(params, accountId)

      logger.info('创建定时微博爬取任务成功', {
        taskId,
        keywords: validKeywords,
        keywordCount: validKeywords.length,
        interval: params.interval,
        maxPages: params.maxPages,
        enabled: params.enabled,
        accountId,
        includeComments: params.includeComments,
        includeReposts: params.includeReposts
      })

      return taskId

    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error)
      logger.error('创建定时微博爬取任务失败', {
        keywords,
        accountId,
        options,
        error: errorMessage
      })
      throw error
    }
  }

  /**
   * 更新定时任务
   */
  async updateScheduledTask(
    taskId: string,
    updates: {
      keywords?: string[]
      interval?: number
      maxPages?: number
      enabled?: boolean
      cronExpression?: string
    }
  ): Promise<void> {
    try {
      // 验证任务是否存在
      const taskEntity = await useEntityManager(async m => {
        const taskRepo = m.getRepository(Task)
        return await taskRepo.findOne({ where: { id: taskId } })
      })
      if (!taskEntity || taskEntity.type !== 'scheduled') {
        throw new Error(`定时任务不存在: ${taskId}`)
      }

      const task = taskEntity.toScrapeTask()

      // 验证更新参数
      if (updates.keywords && updates.keywords.length === 0) {
        throw new Error('关键字列表不能为空')
      }

      if (updates.interval && updates.interval < 60 * 1000) {
        throw new Error('执行间隔不能少于1分钟')
      }

      if (updates.maxPages && (updates.maxPages < 1 || updates.maxPages > 20)) {
        throw new Error('最大页数必须在1-20之间')
      }

      // 构建更新参数
      const updateParams: Partial<ScheduledTaskParams> = {}

      if (updates.keywords) {
        const validKeywords = updates.keywords.filter(keyword =>
          keyword && typeof keyword === 'string' && keyword.trim().length > 0
        )
        if (validKeywords.length === 0) {
          throw new Error('没有有效的关键字')
        }
        updateParams.keywords = validKeywords
      }

      if (updates.interval !== undefined) updateParams.interval = updates.interval
      if (updates.maxPages !== undefined) updateParams.maxPages = updates.maxPages
      if (updates.enabled !== undefined) updateParams.enabled = updates.enabled
      if (updates.cronExpression !== undefined) updateParams.cronExpression = updates.cronExpression

      // 更新任务
      await this.scheduler.updateScheduledTask(taskId, updateParams)

      logger.info('更新定时任务成功', {
        taskId,
        updates: updateParams
      })

    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error)
      logger.error('更新定时任务失败', {
        taskId,
        updates,
        error: errorMessage
      })
      throw error
    }
  }

  /**
   * 删除定时任务
   */
  async deleteScheduledTask(taskId: string): Promise<void> {
    try {
      // 验证任务是否存在
      const taskEntity = await useEntityManager(async m => {
        const taskRepo = m.getRepository(Task)
        return await taskRepo.findOne({ where: { id: taskId } })
      })
      if (!taskEntity || taskEntity.type !== 'scheduled') {
        throw new Error(`定时任务不存在: ${taskId}`)
      }

      // 删除任务
      await this.scheduler.removeScheduledTask(taskId)

      logger.info('删除定时任务成功', { taskId })

    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error)
      logger.error('删除定时任务失败', {
        taskId,
        error: errorMessage
      })
      throw error
    }
  }

  /**
   * 获取所有定时任务
   */
  async getAllScheduledTasks(): Promise<ScrapeTask[]> {
    try {
      const taskEntities = await useEntityManager(async m => {
        const taskRepo = m.getRepository(Task)
        return await taskRepo.find()
      })
      const scheduledTaskEntities = taskEntities.filter(task => task.type === 'scheduled')
      const scheduledTasks = scheduledTaskEntities.map(entity => entity.toScrapeTask())
      return scheduledTasks

    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error)
      logger.error('获取定时任务列表失败', { error: errorMessage })
      throw error
    }
  }

  /**
   * 立即执行定时任务
   */
  async executeScheduledTaskNow(taskId: string): Promise<void> {
    try {
      // 验证任务是否存在
      const taskEntity = await useEntityManager(async m => {
        const taskRepo = m.getRepository(Task)
        return await taskRepo.findOne({ where: { id: taskId } })
      })
      if (!taskEntity || taskEntity.type !== 'scheduled') {
        throw new Error(`定时任务不存在: ${taskId}`)
      }
      const task = taskEntity.toScrapeTask()

      const params = task.params as ScheduledTaskParams
      if (!params.enabled) {
        throw new Error('任务已禁用，无法执行')
      }
      // 立即执行任务
      await this.scheduler.executeTaskNow(taskId)
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error)
      logger.error('立即执行定时任务失败', {
        taskId,
        error: errorMessage
      })
      throw error
    }
  }

  /**
   * 执行完整的微博爬取工作流
   */
  async executeWeiboWorkflow(
    keywords: string[],
    accountId: string,
    options: {
      maxPages?: number
      sendToMQ?: boolean
    } = {}
  ): Promise<WorkflowStats> {
    if (this.isRunning) {
      throw new Error('工作流正在运行中，请等待完成后再试')
    }

    this.isRunning = true
    this.currentStats = {
      totalKeywords: keywords.length,
      processedKeywords: 0,
      totalWeibos: 0,
      successfulWeibos: 0,
      failedWeibos: 0,
      startTime: new Date()
    }

    try {
      // 获取账号信息
      const account = await useEntityManager(async m => {
        const accountRepo = m.getRepository(Account)
        return await accountRepo.findOne({ where: { id: parseInt(accountId) } })
      })
      if (!account) {
        throw new Error('账号不存在或已失效')
      }

      // 解析cookies字符串
      const cookiesArray = typeof account.cookies === 'string'
        ? JSON.parse(account.cookies)
        : account.cookies

      const cookies = cookiesArray.map((cookie: any) => ({
        name: cookie.name,
        value: cookie.value,
        domain: cookie.domain,
        path: cookie.path
      }))

      const cookieString = cookies.map((cookie: any) =>
        `${cookie.name}=${cookie.value}`
      ).join('; ')

      // 并发处理关键字
      const concurrentLimit = Math.min(this.config.maxConcurrentKeywords, keywords.length)
      const keywordChunks = this.chunkArray(keywords, concurrentLimit)

      for (const chunk of keywordChunks) {
        await Promise.all(chunk.map(keyword => 
          this.processKeyword(keyword, cookieString, options.maxPages || this.config.maxPagesPerKeyword)
        ))
      }

      this.currentStats.endTime = new Date()
      this.currentStats.duration = this.currentStats.endTime.getTime() - this.currentStats.startTime.getTime()
      return { ...this.currentStats }
    } catch (error) {
      logger.error('微博爬取工作流执行失败', error)
      throw error
    } finally {
      this.isRunning = false
    }
  }

  /**
   * 处理单个关键字 - 使用 crawlerBase 进行增量爬取
   */
  private async processKeyword(keyword: string, cookies: string, maxPages: number = 50): Promise<void> {
    try {
      await creawlLatestWeiboByKeyword(keyword, cookies)
    } catch (error) {
      logger.error('处理关键字失败', { keyword, error })
      throw error
    }
  }


  /**
   * 获取当前工作流统计
   */
  getCurrentStats(): WorkflowStats | null {
    return this.currentStats
  }

  /**
   * 检查工作流是否正在运行
   */
  isWorkflowRunning(): boolean {
    return this.isRunning
  }

  /**
   * 更新工作流配置
   */
  updateConfig(config: Partial<WorkflowConfig>): void {
    this.config = { ...this.config, ...config }
    logger.info('工作流配置已更新', this.config)
  }

  /**
   * 将数组分块
   */
  private chunkArray<T>(array: T[], chunkSize: number): T[][] {
    const chunks: T[][] = []
    for (let i = 0; i < array.length; i += chunkSize) {
      chunks.push(array.slice(i, i + chunkSize))
    }
    return chunks
  }
}
